﻿#include "stdafx.h"
#include "lex.h"
#include "AstLet.h"
#include "AstGet.h"
#include "AstIf.h"
#include "AstIs.h"
#include "AstBinary.h"
#include "AstUnary.h"
#include "AstLoop.h"
#include "AstReturn.h"
#include "AstClass.h"
#include "AstGetClass.h"
#include "AstConstant.h"
#include "AstTuple.h"
#include "AstFunction.h"
#include "AstValue.h"
#include "AstTupleSpread.h"
#include "AstProtected.h"
#include "AstDot.h"
#include "AstConst.h"
#include "AstEnum.h"
#include "AstSwitch.h"
#include "AstTry.h"
#include "AstNew.h"
#include "AstInterface.h"
#include "SArrayType.h"
#include "AstInc.h"
#include "TupleType.h"
#include "AstBased.h"
#include "SIntegerType.h"
#include "AstPackage.h"
#include "AstImport.h"
#include "AstStringList.h"
#include "AstStringLiteral.h"
#include "AstFloatConstant.h"
#include "AstSequence.h"
#include "AstCall.h"
#include "AstSplice.h"
#include "AstDelete.h"
#include "AstIndex.h"
#include "AstDef.h"
#include "AstSet.h"
#include "AstList.h"
#include "AstEmpty.h"
#include "AutoType.h"
#include "ClassInstanceType.h"
#include "token.h"
#include "Temporary.h"
#include "Parameter.h"

using namespace llvm;
std::vector< status_t > status;
status_t current = prog;
extern AstPackage* currentPackage;

inline void moveLines(std::vector<AstNode*>& block, Temporary* x) {
	if (x) {
		block = std::move(x->lines);
		delete x;
	}
}

AstType* to_type(AstNode* p) {
	return p ? dynamic_cast<AstType*>(p) : nullptr;
}

void packageName(char * name)
{
	currentPackage->names.push_back(name);
}

AstNode * createImport(char * name)
{
	auto*p = new AstImport();
	p->identifiers.push_back(name);
	return p;
}

AstNode * appendImportName(AstNode * n, char * name)
{
	auto*p = dynamic_cast<AstImport*>(n);
	p->identifiers.push_back(name);
	return p;
}

void packageImport(AstNode * n)
{
	auto*p = dynamic_cast<AstImport*>(n);
	currentPackage->imports.push_back(p);
}

void setPackageLines(Temporary * a)
{
	currentPackage->lines = std::move(a->lines);
	delete a;
}

AstNode* let(const std::string& name, AstNode* value) {
	auto p = new AstLet();
	p->name = name;
	p->right = value;
	return p;
}

AstNode*  binary(int op, AstNode* left, AstNode* right) {
	if ('.' == op) {
		return new AstDot(left, right);
	}
		
	return new AstBinary(op, left, right);
}

AstNode * binaryIs(AstNode * left, AstType * right)
{
	auto p = new AstIs();
	p->expr = left;
	p->type = right;
	return p;
}

Parameter* defType(AstType * type, char * name, AstNode* value)
{
	auto*p = new Parameter(name ? name : ":nil", type);
	p->value = value;
	return p;
}

Temporary * createLines(AstNode * line)
{
	auto* p = new Temporary();
	if (line) p->lines.push_back(line);
	return p;
}

Temporary * createLines(AstType * line)
{
	auto* p = new Temporary();
	if (line) p->types.push_back(line);
	return p;
}

Temporary* appendLines(Temporary * lines, AstType * line)
{
	if (!lines)	lines = new Temporary();
	if (line)		lines->types.push_back(line);
	return lines;
}

Temporary * appendLines(Temporary * lines, AstNode * line)
{
	if (!lines) lines = new Temporary();
	if (line)
		lines->lines.push_back(line);
	return lines;
}

AstNode * createStringVector(char * s)
{
	auto* p = new AstStringList();
	p->values.push_back(s);
	return p;
}

AstNode * appendStringItem(AstNode * list, char * var)
{
	auto *p = dynamic_cast<AstStringList*>(list);
	p->values.push_back(var);
	return p;
}

AstNode * link(AstNode * left, AstNode * right)
{
	AstList* p = dynamic_cast<AstList*>(left);
	if (!p) {
		p = new AstList();
		p->lines.push_back(left);
	}
	p->lines.push_back(right);
	return p;
}

AstNode* getVar(const char* name, bool right) {
	auto p = new AstGet();
	p->name = name;
	p->right = right;
	return p;
}

AstNode* makeValue(const char* name, int32_t v) {
	auto a = new AstConstant(name);
	a->set_value(v);
	return a;
}

AstNode* makeValue(const char* name, int64_t v) {
	auto a = new AstConstant(name);
	a->set_value(v);
	return a;
}

AstNode* makeValue(const char* name, float v) {
	return new AstFloatConstant(name, v, false);
}

AstNode* makeValue(const char* name, double v) {
	return new AstFloatConstant(name, v, true);
}

AstNode* makeValue(const char* name, bool v) {
	auto a = new AstConstant(name);
	a->set_value(v);
	return a;
}

AstNode* makeValue(const char* v) {
	// TODO：utf8 支持？
	return new AstStringLiteral(v);
}

AstNode* makeIf(AstNode* cond, Temporary* thenBlock) {
	auto p = new AstIf();
	p->condition = cond;
	moveLines(p->thenBlock, thenBlock);
	return p;
}

AstNode* setElse(AstNode* ifCond, Temporary* elseBlock) {
	auto p = dynamic_cast<AstIf*>(ifCond);
	moveLines(p->elseBlock, elseBlock);
	return ifCond;
}

AstNode* makeWhile(AstNode* cond, Temporary* block) {
	auto p = new AstLoop();
	p->cond = cond;
	moveLines(p->block, block);
	return p;
}

AstNode* makeFor(Parameter* let, AstNode* cond, AstNode* inc, Temporary* block) {
	auto p = new AstLoop();
	if (let) {
		auto d=new AstDef();
		d->type = let->type;
		d->vars.push_back(*let);
		p->let = d;
	}
	
	p->cond = cond;
	p->inc = inc;
	moveLines(p->block, block);
	return p;
}

AstNode * unary(int op, AstNode * v)
{
	return new AstUnary(op, v);
}

AstNode* unaryAfter(int op, AstNode* v) {
	auto *p = new AstUnary(op, v);
	p->after = true;
	return p;
}

AstNode * createFunction(int funcType, const std::string& name, Temporary * parameters, Temporary * ret, Temporary * block)
{
	auto* p = new AstFunction();
	p->name = name;
	p->funcType = (AstFunction::FunctionType)funcType;
	moveLines(p->block, block);

	if (parameters) {
		if(!parameters->params.empty())
			p->paremeters=std::move(parameters->params);
		if (parameters->var) {
			p->variable = parameters->var->type;
			p->variableName = parameters->var->name;
		}
		delete parameters;
	}

	if (ret) {
		p->rets = std::move(ret->params);
		delete ret;
	}

	return p;
}

AstNode * addFunctionBlock(AstNode *node, Temporary * block)
{
	auto p=dynamic_cast<AstFunction*>(node);
	moveLines(p->block, block);
	return p;
}

AstNode * createOperator(int oper, Temporary * variables, Temporary * ret, Temporary * block)
{
	auto n = "operator " + operator_to_str(oper);
	return createFunction(7, n, variables, ret, block);
}

AstType * createInterface(char * name, Temporary * block)
{
	auto *p = new AstInterface();
	p->name = name;
	moveLines(p->block, block);
	return p;
}

Temporary * setVariable(Temporary *p, Parameter * block)
{
	if (!p) p = new Temporary();
	p->var = block;
	return p;
}

AstNode* makeSplice(AstNode* expr, AstNode* begin, AstNode* end) {
	auto p = new AstSplice();
	p->expr = expr;
	p->begin = begin;
	p->end = end;
	return p;
}

AstNode * makeIndex(AstNode * expr, AstNode * x)
{
	auto p = new AstIndex();
	p->expr = expr;
	p->index = x;
	return p;
}

AstNode* makeDelete(AstNode* expr) {
	auto *p = new AstDelete();
	p->expr = expr;
	return p;
}

AstNode* callReturn(AstNode * val)
{
	AstReturn* p = new AstReturn();
	p->returnValues.push_back(val);
	return p;
}

AstType * getFuncType()
{
	return new AstType(AstType::FunctionTyID);
}

AstType * makeArray(AstType * type, AstNode* list)
{
	return new SArrayType(type, list);
}

AstNode* makeSequence(AstNode* node) {
	return new AstSequence(node);
}

AstNode * makeEmpty()
{
	return new AstEmpty();
}

AstNode * makeNull()
{
	return new AstValue();
}

AstType* getType(int type_id) {
	//"var"	yylval.type = 0;	return ITYPE;	/* 内部变量 */
	//"bool"		yylval.type = 1;	return ITYPE;
	//"byte"		yylval.type = 2;	return ITYPE;
	//"char"		yylval.type = 3;	return ITYPE;
	//"short"		yylval.type = 4;	return ITYPE;
	//"int"		    yylval.type = 5;	return ITYPE;
	//"long"		yylval.type = 6;	return ITYPE;
	//"float"		yylval.type = 7;	return ITYPE;
	//"double"	yylval.type = 8;	return ITYPE;
	//"string"	yylval.type = 9;	return ITYPE;
	//"any"		yylval.type = 10;	return ITYPE;

	switch (type_id)
	{
	case 0:
		return new AutoType();
	case 1:
		return SIntegerType::get(1);
	case 2:
		return SIntegerType::get(8);
	case 3:
		return SIntegerType::get(32, true);	// unsigned
	case 4:
		return SIntegerType::get(16);
	case 5:
		return SIntegerType::get(32);
	case 6:
		return SIntegerType::get(64);
	case 7:
		return AstType::floatType;
	case 8:
		return AstType::doubleType;
	case 9:
		return AstType::stringType;
	case 10:
		return AstType::anyType;
	default:
		throw std::runtime_error("未知类型");
	}
}

AstType * getClassType(char * name)
{
	auto p = new AstGetClass();
	p->name = name;
	return p;
}

AstNode* makeTuple(AstNode* elem, AstNode* list)
{
	auto* p = new AstTuple();
	p->elements.push_back(elem);

	AstList* x = dynamic_cast<AstList*>(list);
	if (x) {
		for (auto *i : x->lines)
			p->elements.push_back(i);
		delete x;
	}
	else {
		p->elements.push_back(list);
	}

	return p;
}

AstNode * tupleResolve(Temporary * left, AstNode * tuple)
{
	std::cout << "tupleResolve: " << tuple->name << std::endl;
	auto spread = new AstTupleSpread();
	spread->tuple = tuple;

	for (auto i : left->lines) {
		spread->vars.push_back(i->name);
		delete i;
	}
	return spread;
}

AstNode* makeClass(
	int type,
	char * name,
	AstType* inherit,
	Temporary* block
)
{
	auto *p = new AstClass();
	p->name = name;
	p->singleton = (type == 1);
	if (inherit) p->inherit = (AstGetClass*)inherit;
	moveLines(p->block, block);
	return p;
}

AstNode* setProtected()
{
	return new AstProtected();
}

AstNode * makeConst(char * name, AstNode * value)
{
	AstConst *p = new AstConst();
	p->name = name;
	p->expr = value;
	return p;
}

AstNode * createSwitch(AstNode * cond, Temporary * o)
{
	auto *p = new AstSwitch();
	p->expression = cond;
	for (auto i : o->lines) {
		p->cases.push_back(dynamic_cast<AstCase*>(i));
	}
	delete o;
	return p;
}

AstNode * makeGet(char * name, Temporary * block)
{
	/*	等同
	func operator get() => var valueName{
	}
	*/

	// TODO: new

	auto *p = new AstFunction();
	p->name = "get " + std::string(name);
	Parameter o;
	o.name = name;
	p->rets.push_back(std::move(o));
	moveLines(p->block, block);
	return p;
}

/*
	set(int v){
	}
*/
AstNode * makeSet(char * name, AstType* type, char* id, Temporary * block)
{
	auto *p = new AstSet();
	if (name) p->name = name;
	p->type = type;
	if (id) {
		p->name = std::string(id);
	}
	if (block)	moveLines(p->block, block);
	return p;
}

AstNode * makeBased(AstNode * expr, Temporary * block)
{
	auto p = new AstBased();
	p->expr = expr;
	moveLines(p->block, block);
	return p;
}

AstNode * createCase(Temporary * cond, Temporary * block)
{
	auto *p = new AstCase();
	if (cond) {
		p->conditions = std::move(cond->lines);
		delete cond;
	}

	moveLines(p->block, block);
	return p;
}

AstNode * makeCatch(Temporary * e, char * name, Temporary * lines)
{
	auto *p = new AstTryCatch();
	moveLines(p->block, lines);
	p->name = name;
	p->exception_types = e->types;
	delete e;
	return p;
}

AstNode * createTry(Temporary * block, Temporary * catchs, Temporary * finallyBlock)
{
	auto *p = new AstTry();
	moveLines(p->block, block);
	if (catchs) {
		for (auto i : catchs->lines) {
			auto x = dynamic_cast<AstTryCatch*>(i);
			assert(x);
			p->catchs.push_back(x);
		}
		delete catchs;
	}
	moveLines(p->finallyBlock, finallyBlock);
	return p;
}

AstNode * makeInc(AstNode * expr, bool isInc)
{
	auto p = new AstInc();
	p->expr = expr;
	p->isInc = isInc;
	return p;
}

AstNode * createEnum(char * name, Temporary * items)
{
	auto* p = new AstEnum();
	p->name = name;
	for (auto &i : items->lines) {
		AstLet *let = dynamic_cast<AstLet*>(i);
		assert(let);
		p->values.push_back(let);
	}
	delete items;
	return p;
}

AstNode * makeCall(char * name, Temporary* templateArgs, Temporary * a)
{
	auto *p = new AstCall();
	p->name = name;
	if (templateArgs) {
		for (auto i : templateArgs->params) {
			p->templateArgs.push_back(i.type);
		}
	}
	if (a) {
		p->arguments = std::move(a->params);
		delete a;
	}
	return p;
}

AstNode * createNew(AstType* type, char * name, Temporary * args)
{
	auto *p = new AstNew();
	p->type = type;
	p->name = name;

	if (args) {
		p->blocks = std::move(args->lines);
		delete args;
	}
	return p;
}

AstNode * createDef(Parameter * def)
{
	auto *p = new AstDef();
	p->type = def->type;
	p->vars.push_back(std::move(*def));
	delete def;
	return p;
}

AstNode * appendDef(AstNode * def, char * name, AstNode * value)
{
	auto *d = dynamic_cast<AstDef*>(def);
	d->vars.push_back(Parameter(name, value));
	return def;
}

Parameter * makeParam(char * name, AstType * type)
{
	if (name)
		return new Parameter(std::string(name), type, nullptr);
	else
		return new Parameter("", type, nullptr);
}

Parameter * makeParam(AstNode * node)
{
	return new Parameter(node);
}

Temporary * createVector(Parameter * param)
{
	auto p=new Temporary();
	p->params.push_back(std::move(*param));
	delete param;
	return p;
}

Temporary * appendItem(Temporary * vec, Parameter * param)
{
	vec->params.push_back(std::move(*param));
	delete param;
	return vec;
}
